﻿Friend Class ConfigFuncs

    Private Shared trimChars() As Char = {";"c, " "c}

    Private Shared Function getValue(ByRef sectionName As String, ByRef keyName As String, ByRef iniData As List(Of String)) As String
        Dim findSection As Boolean = False

        For Each line As String In iniData
            If findSection = False Then
                If (line.ToLower = sectionName) Then findSection = True
                Continue For
            End If

            If GetKeyName(line).ToLower = keyName Then
                Return GetKeyValue(line)
            End If
            If line.TrimStart.StartsWith("[") Then Exit For
        Next

        Return Nothing
    End Function

    Private Shared Function getValue(ByRef keyName As String, ByRef iniData As List(Of String)) As String
        For Each line As String In iniData
            If GetKeyName(line).ToLower = keyName Then
                Return GetKeyValue(line)
            End If
        Next
        Return Nothing
    End Function

    Private Shared Function setValue(ByRef sectionName As String, ByRef keyName As String, ByRef value As String, ByRef iniData As List(Of String)) As Boolean
        Dim findSection As Boolean = False

        For n As Integer = 0 To iniData.Count - 1
            If findSection = False Then
                If (iniData(n).ToLower = sectionName) Then findSection = True
                Continue For
            End If

            Dim key = GetKeyName(iniData(n)).TrimStart(trimChars) 'изменяет закоментированный параметр
            If key.ToLower = keyName Then
                iniData(n) = key & "=" & value 'устанавливаем
                Return True
            End If

            If iniData(n).TrimStart.StartsWith("[") Then Exit For
        Next
        Return False
    End Function

    Private Shared Function setValue(ByRef keyName As String, ByRef value As String, ByRef iniData As List(Of String)) As Boolean
        For n As Integer = 0 To iniData.Count - 1
            Dim key = GetKeyName(iniData(n)).TrimStart(trimChars) 'изменяет закоментированный параметр
            If key.ToLower = keyName Then
                iniData(n) = key & "=" & value 'устанавливаем
                Return True
            End If
        Next
        Return False
    End Function

    Friend Shared Function GetKeyName(ByRef str As String) As String
        Dim m As Integer = str.IndexOf("="c)
        If m <= 0 Then Return String.Empty

        Dim key = str.Substring(0, m).Trim() 'возвращаем
        Return key
    End Function

    Friend Shared Function GetKeyValue(ByRef str As String) As String
        Dim m As Integer = str.IndexOf("="c)
        If (m <= 0) Then Return Nothing

        If (m = (str.Length - 1)) Then Return String.Empty

        m += 1
        Return str.Substring(m, str.Length - m).Trim 'возвращаем
    End Function

    ''' <summary>
    ''' Получает значение из конфигурационного файла sfall
    ''' </summary>
    Friend Shared Function GetConfigIniValue(ByVal keyName As String) As String
        keyName = keyName.ToLower

        Dim value = getValue(keyName, sfallIni)
        If value IsNot Nothing Then Return value

        Return getValue(keyName, ddrawIni)
    End Function

    ''' <summary>
    ''' Получает значение из конфигурационного файла sfall
    ''' </summary>
    Friend Shared Function GetConfigIniValue(ByVal sectionName As String, ByVal keyName As String) As String
        keyName = keyName.ToLower
        sectionName = sectionName.ToLower

        Dim value = getValue(sectionName, keyName, sfallIni)
        If value IsNot Nothing Then Return value

        Return getValue(sectionName, keyName, ddrawIni)
    End Function

    ''' <summary>
    ''' Получает значение из указанного ini файла
    ''' </summary>
    Friend Shared Function GetIniValue(ByVal section As String, ByVal key As String, ByRef iniData() As String) As String
        If iniData Is Nothing Then Return Nothing

        section = section.ToLower
        key = key.ToLower

        For n As Integer = 0 To UBound(iniData)
            If iniData(n).ToLower = section Then
                For m As Integer = n + 1 To UBound(iniData)
                    If iniData(m).TrimStart.StartsWith("[") Then Return Nothing
                    If GetKeyName(iniData(m)).ToLower = key Then Return GetKeyValue(iniData(m))
                Next
                Return Nothing
            End If
        Next

        Return Nothing
    End Function

    Friend Shared Function GetStrValue(ByVal section As String, ByVal key As String, ByVal def As String, ByRef iniData() As String) As String
        Dim value = GetIniValue(section, key, iniData)
        Return If(String.IsNullOrEmpty(value), def, value)
    End Function

    Friend Shared Function GetStrValue(ByVal section As String, ByVal key As String, ByRef iniData As List(Of String)) As String
        Return GetIniValue(section, key, iniData.ToArray)
    End Function

    Friend Shared Function GetIntValue(ByVal section As String, ByVal key As String, ByVal def As Integer, ByRef iniData() As String) As Integer
        Dim value = GetIniValue(section, key, iniData)

        If (String.IsNullOrEmpty(value)) Then Return def

        Dim num As Integer
        If Integer.TryParse(value, num) Then Return num

        Return If(value.StartsWith("0x"), Convert.ToInt32(value, 16), def)
    End Function

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    ''' <summary>
    ''' Устанавливает значение в конфигурационный файл sfall, изменяет закоментированный параметр
    ''' без добавления
    ''' </summary>
    Friend Shared Function SetConfigIniValue(ByVal keyName As String, ByRef value As String) As Boolean
        keyName = keyName.ToLower

        If (setValue(keyName, value, sfallIni)) Then Return True

        Return setValue(keyName, value, ddrawIni)
    End Function

    Friend Shared Function MergeSetConfigIniValue(ByVal section As String, ByVal keyName As String, ByRef value As String) As Boolean
        keyName = keyName.ToLower
        section = section.ToLower
        Return setValue(section, keyName, value, ddrawIni)
    End Function

    ''' <summary>
    ''' Устанавливает значение в указанный ini файл
    ''' без добавления, изменяет закоментированный параметр (force)
    ''' </summary>
    Friend Shared Sub SetIniValue(ByVal section As String, ByVal keyName As String, ByVal value As String, ByRef iniData() As String, Optional ByVal force As Boolean = False)
        If iniData Is Nothing Then Exit Sub

        keyName = keyName.ToLower
        section = section.ToLower

        Dim line As Integer = -1
        For n As Integer = 0 To UBound(iniData)
            If iniData(n).ToLower = section Then
                line = n
                Exit For
            End If
        Next
        If line = -1 Then Exit Sub

        For n As Integer = line + 1 To UBound(iniData)
            If iniData(n).TrimStart.StartsWith("[") Then Exit Sub

            Dim key = GetKeyName(iniData(n)).ToLower
            If (force) Then key = key.TrimStart(trimChars)

            If key = keyName Then
                Dim m As Integer = iniData(n).IndexOf("=", 2)
                'записываем
                If (m >= iniData(n).Length - 1) Then
                    iniData(n) &= value
                Else
                    iniData(n) = iniData(n).Remove(m + 1) & value
                End If
                Exit Sub
            End If
        Next
    End Sub

    ''' <summary>
    ''' Устанавливает значение в указанный ini файл
    ''' с добавлением
    ''' </summary>
    Friend Shared Sub SetIniValue(ByVal sectionName As String, ByVal keyName As String, ByVal value As String, ByRef iniData As List(Of String))
        Dim key = keyName.ToLower

        Dim n = getSectionIndex(sectionName.ToLower, iniData)
        If (n = -1) Then ' сексия не найдена, добавляем в конец
            iniData.Add(sectionName)
            iniData.Add(keyName & "=" & value)
            Return
        End If

        ' ищем опцию
        Dim m As Integer = n
        For i = n + 1 To iniData.Count - 1
            If iniData(i).TrimStart.StartsWith("[") Then
                ' добавляем в секцию
                iniData.Insert(m + 1, "")
                iniData.Insert(m + 1, keyName & "=" & value)
                Exit Sub
            End If

            If (iniData(i).Length > 0) Then
                If GetKeyName(iniData(i)).ToLower = key Then
                    'изменяем
                    n = iniData(i).IndexOf("=", 2)
                    If (n >= iniData(i).Length - 1) Then
                        iniData(i) &= value
                    Else
                        iniData(i) = iniData(i).Remove(n + 1) & value
                    End If
                    Exit Sub
                End If

                m = i ' последняя строка после которой будет записан ключ если таковой не будет найден
            End If
        Next
    End Sub

    Friend Shared Sub SetConfigIniValue(ByVal sectionName As String, ByVal keyName As String, ByVal value As String)
        If (sfallIni.Count) Then
            SetIniValue(sectionName, keyName, value, sfallIni)
        Else
            SetIniValue(sectionName, keyName, value, ddrawIni)
        End If
    End Sub

    ''' Misc functions '''

    Private Shared Function getSectionIndex(ByVal section As String, ByRef iniData As List(Of String)) As Integer
        For n As Integer = 0 To iniData.Count - 1
            If (iniData(n).TrimStart.StartsWith("[") AndAlso iniData(n).Length >= section.Length) Then

                Dim sec = If(iniData(n).Length > section.Length, iniData(n).Remove(section.Length), iniData(n))
                If sec.ToLower = section Then
                    Return n
                End If
            End If
        Next
        Return -1
    End Function

    Private Shared Function getKeyIndex(ByVal key As String, ByRef iniData As List(Of String)) As Integer
        For n As Integer = 0 To iniData.Count - 1
            If GetKeyName(iniData(n)).ToLower = key Then
                Return n
            End If
        Next
        Return -1
    End Function

    Private Shared Function GetIniKeyLineIndex(ByVal key As String, ByRef iniData As List(Of String)) As Integer
        key = key.ToLower
        Return getKeyIndex(key, iniData)
    End Function

    Friend Shared Function GetKeyLineIndex(ByVal key As String) As Integer
        Return GetIniKeyLineIndex(key, ddrawIni)
    End Function

    Friend Shared Function GetIniSectionLineIndex(ByVal section As String, ByRef ini As List(Of String)) As Integer
        section = section.ToLower()
        Return getSectionIndex(section, ini)
    End Function

    Friend Shared Function GetSectionLineIndex(ByVal section As String) As Integer
        Return GetIniSectionLineIndex(section, ddrawIni)
    End Function

End Class
